﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Web;
using SDT.Libraries.Convertor;
using SDT.Libraries.Utilities;
using SDT.Lib.Helpers;

namespace SDT.CrawlSystem.Servers.Filters
{
    /// <summary>
    /// Written by TungNX
    /// </summary>
    public sealed partial class DateFilter : Filter, IDateFilter
    {
        #region Constructors
        private void LoadProperties(XmlNode n)
        {
            if (n == null)
                throw new ArgumentNullException();

            format = n.Attributes["Format"] != null ? n.Attributes["Format"].Value : "dd/MM/yyyy";

            var _n = n.SelectSingleNode("OtherFormats");
            if (_n != null)
            {
                var col = _n.SelectNodes("Other");

                if (col != null && col.Count > 0)
                    foreach (var item in col)
                        formatters.Add(new Formatter(item as XmlNode));
            }
        }

        public DateFilter(XmlNode n, Encoding enc)
            : base(n, enc)
        {
            LoadProperties(n);
        }

        public DateFilter(XmlNode n)
            : base(n)
        {
            LoadProperties(n);
        }
        #endregion

        #region IDateFilter Members
        private string format = null;
        public string Format
        {
            get { return format; }
        }

        private List<Formatter> formatters = new List<Formatter>();
        public IList<Formatter> CustomFormatters
        {
            get { return formatters; }
        }
        #endregion
        /// <summary>
        /// Modified Date: 03/09/2010
        /// Remove tag html
        /// </summary>
        /// <param name="htm"></param>
        /// <param name="txt"></param>
        /// <returns></returns>
        public DateTime DoFilter(string htm, string txt)
        {
            string d = null;

            //Modified Date: 03/09/2010
            //delete if(TheTag != null)   DoHtmFilter(htm,ref d);            
            //Modified Date: 03/09/2010
            d = DoDateFilter(htm, txt, ref d);

            //Add code
            //Create date : 14/09/2010
            //Add function Strip HTML
            d = StripHTML(d);

            try
            {
                d = HttpUtility.HtmlDecode(d);
                //chi ap dung cho trang VEN.VN . Nếu remove langVN thì sẽ mất chứ tháng sáu, tháng bảy, tháng hai... nên xảy ra lỗi
                if (format != VEN)
                    d = CleanLangVN(d);
                //replace duplicate white space
                d = RemoveWhitespaceWithSplit(d);
                //Add Date: 16/10/2010
                //ConvertWhitespacesToSingleSpaces
                d = ConvertWhitespacesToSingleSpaces(d);


                d = d.Trim(new char[] { ':', ' ', '&', '-', ';', '_', '+', '.', ',' });
                d = d.Trim(new char[] { ':', ' ', '&', '-', ';', '_', '+', '.', ',' });
                //Modified Date : 14/09/2010
                //Author: TungNX
                //Description : Process site have special site
                if (IsSpecialSites(format) != string.Empty)
                {
                    return GetDateFromSpecialSite(format, d);
                }

                //Modified Date: Give up subtring

                //d = d.Substring(0, format.Length);

                // If hour have PM
                bool isPM = false;
                isPM = d.Contains("pm");

                var t = DateTime.ParseExact(d, format, null);
                // If hour have PM
                //if (t.Hour >= 12)
                //{                                                 Vietle rào lại ngày 22/09/2011
                //    if (!isPM) t = t.AddHours(-12);
                //}

                return t;
            }
            catch (Exception ex)
            {
                var ret = DateTime.Now;
                foreach (var f in CustomFormatters)
                {
                    var b = true;
                    ret = f.GetDateTime(d, out b);
                    if (!b)
                        return ret;
                }

                return ret;
            }
        }

        #region Clean special character
        private string StripHTML(string htmlString)
        {
            string pattern = @"<(.|\n)*?>";
            return Regex.Replace(htmlString, pattern, string.Empty);

        }
        /// <summary>
        /// Modified Date: TungNX
        /// Don't remove PM, AM format Date add tt
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private string CleanLangVN(string input)
        {
            string[] arrStr = new string[] { "thứ 2", "thứ 3", "thứ 4", "thứ 5", "thứ 6", "thứ 7", "bảy", "hai", "ba", "tư", "năm", "sáu", "Sáu", "bảy", "bẩy", "chủ nhật", "chủ nhật", "(GMT+7)", "GMT+7", "gmt +7", "(gmt + 7)", "gmt+7", "(gmt+7)", "ngày", "thứ", "thứ", "chủ nhật" };
            input = input.ToLower();
            foreach (string s in arrStr)
            {
                input = input.Replace(s.ToLower(), "");
            }

            char[] cEx = new char[] { ',', '-', '|' };
            foreach (char c in cEx)
            {
                input = input.Replace(c, ' ');
            }

            return input;

        }

        /// <summary>
        /// Convert all whitespaces to a single space.
        /// </summary>
        public string ConvertWhitespacesToSingleSpaces(string value)
        {
            value = Regex.Replace(value, @"\s+", " ");
            return value;
        }

        public string RemoveWhitespaceWithSplit(string inputString)
        {
            StringBuilder sb = new StringBuilder();

            string[] parts = inputString.Split(new char[] { ' ', '\n', '\t', '\r', '\f', '\v' }, StringSplitOptions.RemoveEmptyEntries);

            int size = parts.Length;
            for (int i = 0; i < size; i++)
                sb.AppendFormat("{0} ", parts[i]);

            return sb.ToString();
        }
        #endregion

        #region Other Site
        private const string VNEXPRESS = "VNEXPRESS";
        private const string VNECONOMY = "VNECONOMY";
        private const string TUANVIETNAMNET = "TUANVIETNAMNET";
        private const string VNROCK = "VNROCK";
        private const string BONGDA24H = "BONGDA24H";
        private const string STOCKBIZ = "STOCKBIZ";
        private const string VEN = "VEN";
        private const string QUOTEMARK = "QUOTEMARK";

        private const string DMYYYYHMM = "DMYYYYHMM";
        //autopro
        private const string DMYYYYHM = "DMYYYYHM";
        //xzone
        //d/MM/yyyy HH:mm
        private const string DMMYYYYHHMM = "DMMYYYYHHMM";

        //VnMedia
        //Cập nhật lúc 20h07" , ngày 25/09/2010  -
        private const string VNMEDIA = "VNMEDIA";
        //Petrotimes
        // Added by Vietlv : 19/10/2011
        private const string PETROTIMES = "PETROTIMES";
        private const string CHOTHAI = "CHOTHAI";
        private string IsSpecialSites(string format)
        {
            if (format == null)
                return string.Empty;
            switch (format.Trim().ToUpper())
            {
                case VNEXPRESS:
                    return VNEXPRESS.ToUpper();
                case VNECONOMY:
                    return VNECONOMY.ToUpper();
                case TUANVIETNAMNET:
                    return TUANVIETNAMNET.ToUpper();
                case QUOTEMARK:
                    return QUOTEMARK.ToLower();
                case VNROCK:
                    return VNROCK.ToLower();
                case BONGDA24H:
                    return BONGDA24H.ToLower();
                case STOCKBIZ:
                    return STOCKBIZ.ToLower();
                case VEN:
                    return VEN;
                case DMYYYYHMM:
                    return DMYYYYHMM.ToUpper();
                case VNMEDIA:
                    return VNMEDIA.ToUpper();
                case PETROTIMES:                   // Added by Vietlv 19/10/2011
                    return PETROTIMES.ToUpper();
                case CHOTHAI:                   // Added by Vietlv 19/10/2011
                    return CHOTHAI.ToUpper();
                case DMYYYYHM:
                    return DMYYYYHM.ToUpper();
                case DMMYYYYHHMM:
                    return DMMYYYYHHMM.ToUpper();
                default:
                    return string.Empty;
            };

        }

        private DateTime GetDateFromSpecialSite(string format, string inputString)
        {
            switch (format.Trim().ToUpper())
            {
                case VNEXPRESS:
                    return GetDateVnExpress(inputString);
                case VNECONOMY:
                    return GetDateVnEconomy(inputString);
                case TUANVIETNAMNET:
                    return GetDateTuanVietNamNet(inputString);
                case DMYYYYHMM:
                    return GetDateDMYYYYHMM(inputString);
                case VNMEDIA:
                    return GetDateVnMedia(inputString);
                case PETROTIMES:                           // Added by Vietlv 19/10/2011
                    return GetDatePetroTimes(inputString);
                case QUOTEMARK:
                    return FilterQuoteMark(inputString);
                case CHOTHAI:
                    return GetDateChoThaiTimes(inputString);
                case VEN:
                    return GetDateVen(inputString);
                case BONGDA24H:
                    return GetDateBongDa24h(inputString);
                case STOCKBIZ:
                    return GetDateStockBiz(inputString);
                case VNROCK:
                    return GetDateRockVn(inputString);
                case DMYYYYHM:
                    return GetDatedMyyyyHm(inputString);
                case DMMYYYYHHMM:
                    return GetDatedMMyyyyHHmm(inputString);

                default:
                    return DateTime.Now;
            };
        }

        private DateTime GetDatedMMyyyyHHmm(string inputString)
        {
            try
            {
                string retFormatDate = "d/M/yyyy HH:mm";
                return DateTime.ParseExact(inputString, retFormatDate, null);
            }
            catch { return DateTime.Now; }
        }

        private DateTime GetDateVnExpress(string inputString)
        {
            string formatDMMYYYY = "d/MM/yyyy HH:mm";
            string formatDMYYYY = "d/M/yyyy HH:mm";
            string formatDDMYYYY = "dd/M/yyyy HH:mm";
            string formatDDMMYYYY = "dd/MM/yyyy HH:mm";

            string[] Temp = inputString.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);

            if (Temp[0].ToString().Length == 1 && Temp[1].ToString().Length == 1)
                return DateTime.ParseExact(inputString, formatDMYYYY, null);

            if (Temp[0].ToString().Length == 1 && Temp[1].ToString().Length == 2)
                return DateTime.ParseExact(inputString, formatDMMYYYY, null);

            if (Temp[0].ToString().Length == 2 && Temp[1].ToString().Length == 1)
                return DateTime.ParseExact(inputString, formatDDMYYYY, null);

            if (Temp[0].ToString().Length == 2 && Temp[1].ToString().Length == 2)
                return DateTime.ParseExact(inputString, formatDDMMYYYY, null);

            return DateTime.Now;
        }

        private DateTime GetDateDMYYYYHMM(string inputString)
        {
            try
            {
                string retFormatDate = "d/M/yyyy h:mm";
                return DateTime.ParseExact(inputString, retFormatDate, null);
            }
            catch { return DateTime.Now; }
        }

        private DateTime GetDatedMyyyyHm(string inputString)
        {
            try
            {
                string retFormatDate = "d/M/yyyy H:m";
                return DateTime.ParseExact(inputString, retFormatDate, null);
            }
            catch { return DateTime.Now; }
        }


        private DateTime GetDateVnEconomy(string inputString)
        {
            //03/11/2010 09:42
            #region format1
                string formatHHssdMMyyyy = "HH:mm d/MM/yyyy";
                string formatHHssdMyyyy = "HH:mm d/M/yyyy";
                string formatHHssddMyyyy = "HH:mm dd/M/yyyy";
                string formatHHssddMMyyyy = "HH:mm dd/MM/yyyy";
            #endregion
            #region format2
                string formatDMMYYYY = "d/MM/yyyy HH:mm";
                string formatDMYYYY = "d/M/yyyy HH:mm";
                string formatDDMYYYY = "dd/M/yyyy HH:mm";
                string formatDDMMYYYY = "dd/MM/yyyy HH:mm";
            #endregion
            string[] Temp = inputString.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);

            //format 1
            if (Temp[0].ToString().Length == 7 && Temp[1].ToString().Length == 2)
                return DateTime.ParseExact(inputString, formatHHssdMMyyyy, null);

            if (Temp[0].ToString().Length == 7 && Temp[1].ToString().Length == 1)
                return DateTime.ParseExact(inputString, formatHHssdMyyyy, null);

            if (Temp[0].ToString().Length == 8 && Temp[1].ToString().Length == 1)
                return DateTime.ParseExact(inputString, formatHHssddMyyyy, null);

            if (Temp[0].ToString().Length == 8 && Temp[1].ToString().Length == 2)
                return DateTime.ParseExact(inputString, formatHHssddMMyyyy, null);

            //format 2
            if (Temp[0].ToString().Length == 1 && Temp[1].ToString().Length == 1)
                return DateTime.ParseExact(inputString, formatDMYYYY, null);

            if (Temp[0].ToString().Length == 1 && Temp[1].ToString().Length == 2)
                return DateTime.ParseExact(inputString, formatDMMYYYY, null);

            if (Temp[0].ToString().Length == 2 && Temp[1].ToString().Length == 1)
                return DateTime.ParseExact(inputString, formatDDMYYYY, null);

            if (Temp[0].ToString().Length == 2 && Temp[1].ToString().Length == 2)
                return DateTime.ParseExact(inputString, formatDDMMYYYY, null);
            return DateTime.Now;
        }

        private DateTime GetDateTuanVietNamNet(string inputString)
        {
            string format = "dd/MM/yyyy HH:ss";
            if (inputString.Contains("GMT+7"))
                return DateTime.ParseExact(inputString, format, null);
            if (inputString.Contains("giờ"))
            {
                int intDate = Convert.ToInt16(StringHelper.GetStringByGroup(inputString, @"\d{1,2}"));

                return DateTime.Now.AddHours((-1) * intDate);
            }

            else { }

            return DateTime.Now;
        }


        //VnMedia
        //Cập nhật lúc 20h07" , ngày 25/09/2010  -
        private DateTime GetDateVnMedia(string inputString)
        {
            try
            {
                inputString = inputString.Replace("h", ":");
                char cSp = '"';

                char cRep = ' ';
                inputString = inputString.Replace(cSp, cRep);
                //replace " and '
                inputString = inputString.Replace("'", "");

                inputString = RemoveWhitespaceWithSplit(inputString);
                inputString = inputString.Trim();
                //inputString = Regex.Replace(inputString, @"\s", "");

                string retFormatDate = "HH:mm dd/MM/yyyy";
                return DateTime.ParseExact(inputString, retFormatDate, null);
            }
            catch (Exception ex)
            {
                return DateTime.Now;
            }
        }
        //PetroTimes
        // Added by Vietlv
        private DateTime GetDatePetroTimes(string inputString)
        {
            try
            {
                string []Temp = inputString.Split(' '); // 10:08 sáng   tháng mười 14  2011
                int y = Convert.ToInt32(Temp[5]);
                int day = Convert.ToInt32(Temp[4]);
                string hms = Temp[0].ToString();
                string[] hs = hms.Split(':');
                int h = Convert.ToInt32(hs[0]);
                int m = Convert.ToInt32(hs[1]);
                string tem = TextHelper.ToUrlFriendly(Temp[3].ToString());
                int mth = ChangeMonth(tem);
                string session = Temp[1].ToString();
                if (session.ToLower().Contains("chiều"))
                {
                    h = h + 12;
                }
                
                DateTime d = new DateTime(y, mth, day, h, m,0);
                return d;
            }
            catch (Exception exp)
            {
                return DateTime.Now;
            }

        }
        private DateTime GetDateChoThaiTimes(string inputString)
        {
            try
            {
                int y = 0; int day = 0; int h = 0; int m = 0; int month = 0;

                string[] Temp = inputString.Split('>'); // Hôm qua, 11:39 AM
                var index = inputString.IndexOf('>');
                var template = inputString.Substring(index + 1);
                if (template.ToLower().Contains("hôm"))
                {
                    DateTime ti = DateTime.Now;
                    if (template.ToLower().Contains("hôm qua"))
                    {
                        ti = DateTime.Now.AddDays(-1.00);
                    }
                    var tem1 = template.Split(',');
                    var tem2 = tem1[1].Trim().Split(' ');
                    var tem3 = tem2[0].Trim().Split(':');
                    h = Convert.ToInt32(tem3[0]);
                    m = Convert.ToInt32(tem3[1]);
                    if (template.ToLower().Contains("pm")) h += 12;
                    DateTime d = new DateTime(ti.Year, ti.Month, ti.Day, h, m, 0);
                    return d;

                }
                else
                {    //05 12 2012 09:42 am
                    template = template.Trim();
                    var tem1 = template.Split(' ');
                    month = Convert.ToInt32(tem1[0]);
                    day = Convert.ToInt32(tem1[1]);
                    y = Convert.ToInt32(tem1[2]);
                    var tem2 = tem1[3].Split(':');
                    h = Convert.ToInt32(tem2[0]);
                    m = Convert.ToInt32(tem2[1]);
                    if (template.ToLower().Contains("pm")) h += 12;
                    DateTime d = new DateTime(y, month, day, h, m, 0);
                    return d;
                }
            }
            catch (Exception exp)
            {
                return DateTime.Now;
            }

        }
        //chuyen month sang so
        public int ChangeMonth(string input)
        {
            string month = input.ToLower();
            int outPut = 0;
            switch (month)
            {
                case "giêng": {outPut = 1; break;}
                    //break;
                case "hai": {outPut = 2; break;}
                    //break;
                case "ba": {outPut = 3; break;}
                    //break;
                case "tư": {outPut = 4; break;}
                    //break;
                case "năm": {outPut = 5; break;}
                    //break;
                case "sáu": {outPut = 6; break;}
                    //break;
                case "bảy": {outPut = 7; break;}
                    //break;
                case "tám": {outPut = 8; break;}
                    //break;
                case "chín": {outPut = 9; break;}
                    //break;
                case "mười": {outPut = 10; break;}
                    //break;
                case "mười một": {outPut = 11; break;}

                case "mười hai": { outPut = 12; break; }
                    //break;
                case "mot": { outPut = 1; break; }
                case "bon": { outPut = 4; break; }
                case "nam": { outPut = 5; break; }
                case "sau": { outPut = 6; break; }
                case "bay": { outPut = 7; break; }
                case "tam": { outPut = 8; break; }
                case "chin": { outPut = 9; break; }
                case "muoi": { outPut = 10; break; }
                case "muoi mot": { outPut = 11; break; }
                case "muoi hai": { outPut = 12; break; }
            }
            return outPut;
        }
        //xu ly cho trang ven.vn
        public DateTime GetDateVen(string input)
        {
            try
            {
                string[] arrDate = input.Split(' ');
                DateTime d;
                if (arrDate.Length == 6)
                {
                    int day = int.Parse(arrDate[0].ToString());
                    int month = ChangeMonth(arrDate[2].ToString());
                    int year = int.Parse(arrDate[3].ToString());
                    int[] arrTime = ArrayHour(arrDate[4].Trim().ToString());
                    //--------
                    d = new DateTime(year, month, day, arrTime[0], arrTime[1], arrTime[2]);
                }
                else
                {
                    int day = int.Parse(arrDate[0].ToString());
                    string month1 = arrDate[2].ToString();
                    string month2 = arrDate[3].ToString();
                    string month12 = month1 + " " + month2;
                    int month = ChangeMonth(month12.ToString());
                    int year = int.Parse(arrDate[4].ToString());
                    int[] arrTime = ArrayHour(arrDate[5].Trim().ToString());
                    //--------
                    d = new DateTime(year, month, day, arrTime[0], arrTime[1], arrTime[2]);
                }
                return d;
            }
            catch (Exception ex) { return DateTime.Now; }
        }
        //T7, Tháng 10 16 2010
        //xu ly cho trang vnrock.com
        public DateTime GetDateRockVn(string input)
        {
            try
            {
                string[] arrDate = input.Split(' ');
                int day = int.Parse(arrDate[3].ToString());
                int month = int.Parse(arrDate[2].ToString());
                int year = int.Parse(arrDate[4].ToString());
                //---------
                DateTime d = new DateTime(year, month, day);
                return d;
            }
            catch (Exception ex)
            {
                return DateTime.Now;
            }
        }

        //xu ly cho trang bongda24h.vn
        public DateTime GetDateBongDa24h(string input)
        {
            try
            {
                string[] arr = input.Split(' ');
                int day = int.Parse(arr[0].ToString());
                int month = int.Parse(arr[2].ToString());
                int year = int.Parse(arr[3].ToString());
                string hm = arr[7].ToString();
                int[] arrTime = ArrayHour(hm);
                int second = 0;
                //--------------
                DateTime d = new DateTime(year, month, day, arrTime[0], arrTime[1], second);
                return d;
            }
            catch (Exception ex)
            {
                return DateTime.Now;

            }
        }
        //xu ly cho trang stockBiz.vn
        public DateTime GetDateStockBiz(string input)
        {
            //05/11/2010 7:15:00 sa
            try
            {
                string[] arr = input.Split(' ');
                int day = int.Parse(arr[0].Split('/')[0].ToString());
                int month = int.Parse(arr[0].Split('/')[1].ToString());
                int year = int.Parse(arr[0].Split('/')[2].ToString());
                string hm = arr[1].ToString();
                int[] arrTime = ArrayHour(hm);
                int second = 0;
                DateTime d = DateTime.Now;
                if (arr[2].ToString().Equals("ch"))
                    d = new DateTime(year, month, day, arrTime[0], arrTime[1], second);
                if (arr[2].ToString().Equals("sa"))
                    d = new DateTime(year, month, day, arrTime[0], arrTime[1], second);

                return d;
            }
            catch (Exception ex)
            {
                return DateTime.Now;

            }
        }
        #endregion


        #region Quote mark
        //VnMedia
        //Cập nhật lúc 20h07' , ngày 25/09/2010  
        /// <summary>
        /// Filter : 0h:7' 3/11/2010
        /// 09h02' 3/11/2010
        /// 09h:02' 3/11/2010
        /// </summary>
        /// <param name="inputString"></param>
        /// <returns></returns>
        public DateTime FilterQuoteMark(string inputString)
        {
            try
            {
                Regex regEx = new Regex("\\'");

                string output;
                output = regEx.Replace(inputString, "");
                //tach dd/mm/yyy va hh:mm
                string[] arrDate = output.Split(' ');

                //inset arr string to integer
                string daymonthyear = arrDate[1].Trim().ToString();
                int[] arrIntDate = ArrayDate(daymonthyear);

                //filter arr Time HH:mm
                int[] arrIntTime = ArrayHour(arrDate[0].Trim().ToString());
                //--------
                DateTime d = new DateTime(arrIntDate[2], arrIntDate[1], arrIntDate[0], arrIntTime[0], arrIntTime[1], arrIntTime[2]);
                return d;
            }
            catch (Exception ex)
            {
                return DateTime.Now;
            }
        }

        //chuyen day/month/year -->mang
        public int[] ArrayDate(string input)
        {
            string objPattern = @"/";
            Regex objReg = new Regex(objPattern);
            string[] objStringCut = objReg.Split(input);
            int[] outPut = new int[] { int.Parse(objStringCut[0].ToString()), int.Parse(objStringCut[1].ToString()), int.Parse(objStringCut[2].ToString()) };
            return outPut;
        }
        //chuyen h:m:second -->mang
        public int[] ArrayHour(string input)
        {
            string[] arrPattern = { "h:", ":", "h" };
            Regex objReg = new Regex(":");
            foreach (var s in arrPattern)
            {
                if (input.Contains(s))
                {
                    objReg = new Regex(s);
                    break;
                }
            }

            string[] objStringCut = objReg.Split(input);
            //khong co second
            int second;
            if (objStringCut.Length == 2)
            {
                second = 0;
            }
            else
            {
                second = (objStringCut[2] != null) ? int.Parse(objStringCut[2].ToString()) : 0;
            }
            int hour = (objStringCut[0] != null) ? int.Parse(objStringCut[0].ToString()) : 0;
            int minutes = (objStringCut[1] != null) ? int.Parse(objStringCut[1].ToString()) : 0;
            int[] outPut = new int[] { hour, minutes, second };
            return outPut;
        }
        #endregion

    }
}